package com.syedu.day16;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.*;

/**
 * 如果连续注册两个用户,如何在登录方法中实现登录???
 */
public class ObjectInputStreamDemo {
    public static void main(String[] args) {
        ObjectInputStreamDemo demo = new ObjectInputStreamDemo();
        //demo.registerUser("admin3", "123456");
        demo.loginUser("admin3", "123456");
    }

    /**
     * 注册用户
     * 把对象写入到目标文件中
     */
    public void registerUser(String username, String password) {
        User user = new User(username, password);
        try (ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("D:\\user.data", true))) {
            outputStream.writeObject(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 登录
     * 从文件中读取用户信息
     */
    public void loginUser(String username, String password) {
        try (ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("D:\\user.data"))) {
           /* User user = (User) inputStream.readObject();
            if (username.equals(user.getUsername()) && password.equals(user.getPassword())) {
                System.out.println("登录成功!");
            } else {
                System.out.println("登录失败!");
            }*/

            boolean success = false;
            while (true) {
                /**
                 * java.io.StreamCorruptedException: invalid type code: AC
                 *
                 * 问题: 使用ObjectOutputStream向文件中追加写多个对象后,读取时,只有第一个对象读取是正确的,读取第二个对象开始就会抛出这个异常,
                 * 该异常为流的结构不完整(多了或者少了)问题.
                 *
                 * 原因: 多次写入对象时,会添加多个文件头,读取时,虽然第一次会自动忽略文件头信息,正确读取,但是后面的读取由于都多了这个文件头信息,
                 * 导致文件流结构的不一致,所以抛出异常
                 *
                 * 解决办法：所以这里要判断是不是第一次写文件，若是则写入头部，否则不写入
                 * https://blog.csdn.net/xcwll_sina/article/details/39370443
                 *
                 * 注意: 此方式相当于自己写一个类来改进官方API的类,当然,我们也可以采用其他方法来处理
                 *
                 * 思路:
                 * 使用集合来存放多个对象,然后把集合写入到目标文件中(不开启追加模式),当需要添加新对象时,是需要读取文件中唯一一个集合对象,并且
                 * 添加新元素即可,然后把集合写回到文件中,因为没有开启追加模式,所以是直接覆盖的,就不存在二次添加,也不会产生多余的文件头
                 */
                User user = (User) inputStream.readObject();
                if (username.equals(user.getUsername()) && password.equals(user.getPassword())) {
                    success = true;
                    break;
                }
            }
            if (success) {
                System.out.println("登录成功!");
            } else {
                System.out.println("登录失败!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

/**
 * 把对象写入到文件中的操作叫做持久化,也叫作序列化,
 * Java中要求被序列化的对象必须实现java.io.Serializable标记接口,才能序列化,否则会抛出异常:
 * java.io.NotSerializableException,不能序列化异常
 *
 * 注意: 实现java.io.Serializable接口后最好还要添加序列化ID,通过idea的配置后,可以在需要产生
 * 序列化id的类名上输入alt+回车来产生serialVersionUID
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
class User implements Serializable {
    //JDK14新出的注解,用来标示序列化ID,大家直接删除忽略即可
    //@Serial
    private static final long serialVersionUID = 6058717196213651322L;
    private String username;

    //transient关键字的作用就是可以在持久化操作中,忽略该属性!
    //private transient String password;
    private String password;
}